﻿using SuperX.Common.BasicService;
using System;
using System.Collections.Generic;
using System.Text;

namespace SuperX.Common.Scheduler
{
    // 
    public class TimerDispatcher : IScheduler, IDisposable
    {
        // 
        public SchedulerPattern Pattern
        {
            get
            {
                return SchedulerPattern.Timing;
            }
        }

        // 
        public ITag Tag { get; set; }

        // 
        public TimerDispatcher(SchedulerSetting setting, string tagPath)
        {
            if (!this._project.Objects.ContainsKey(tagPath))
            {
                return;
            }
            this.Tag = (this._project.Objects[tagPath] as ITag);
            if (this.Tag == null)
            {
                return;
            }
            this._interval = setting.Interval;
            this._useAbsTime = setting.IsUseAbsTime;
            this._absTime = setting.AbsTime;
        }

        // 
        public void Register(Action<SchedulerValue> action)
        {
            this._action = action;
            this.Run(this._project.StartTime);
        }

        // 
        private bool Run(DateTime time)
        {
            if (this.Tag == null || this._action == null || this._isRun)
            {
                return false;
            }
            DateTime nextTriggerTime = time;
            if (this._useAbsTime)
            {
                double num = Math.Round(Math.Abs((time - this._absTime).TotalMilliseconds) % (double)this._interval, 0);
                nextTriggerTime = time.AddMilliseconds((double)this._interval - num);
            }
            this._nextTriggerTime = nextTriggerTime;
            this._isRun = true;
            return true;
        }

        // 
        public void Dispose()
        {
            this._action = null;
        }

        // 
        public void Stop()
        {
            this._isRun = false;
            this.Dispose();
        }

        // 
        public bool Check(out SchedulerValue dispatchValue)
        {
            DateTime now = DateTime.Now;
            dispatchValue = null;
            bool result = false;
            if (now >= this._nextTriggerTime)
            {
                if ((now - this._nextTriggerTime).TotalMilliseconds < (double)this._interval)
                {
                    dispatchValue = new SchedulerValue
                    {
                        TagPath = this.Tag.FullName,
                        Vale = this.Tag.Value,
                        TimeStamp = this.Tag.TimeStamp,
                        Quality = this.Tag.Quality,
                        TriggerTime = now
                    };
                    result = true;
                }
                this.UpdataNextTrggierTime(now);
            }
            return result;
        }

        // 
        private void UpdataNextTrggierTime(DateTime now)
        {
            if ((now - this._nextTriggerTime).TotalMilliseconds > (double)this._interval)
            {
                double num = Math.Round((now - this._nextTriggerTime).TotalMilliseconds % (double)this._interval, 0);
                this._nextTriggerTime = now.AddMilliseconds((double)this._interval - num);
                return;
            }
            this._nextTriggerTime = this._nextTriggerTime.AddMilliseconds((double)this._interval);
        }

        // 
        public void Invoke(SchedulerValue dispatchValue)
        {
            Action<SchedulerValue> action = this._action;
            if (action == null)
            {
                return;
            }
            action(dispatchValue);
        }

        // 
        private readonly IProject _project = BasicServiceManager.GetProjService().Project;

        // 
        private int _interval;

        // 
        private Action<SchedulerValue> _action;

        // 
        private bool _isRun;

        // 
        private bool _useAbsTime;

        // 
        private DateTime _absTime;

        // 
        private DateTime _nextTriggerTime;
    }
}
